﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Library.HttpTools;

namespace iNotesNotification
{
    public class iNotesHtmlHelper : iNotesHelper
    {
        private enum HtmlParseMode
        {
            Open = 0,
            InElement = 1,
            ElementAttribute = 2,
            ClosingElement = 3
        }

        private iNotesMessage _current;
        private string _lastClass = null;
        private iNotesMailbox _mailbox;
        private DateTime _latestMessageDate = DateTime.MinValue;
        private int _numMessages = -1;

        public iNotesHtmlHelper() { }

        public void Refresh()
        {
            _latestMessageDate = DateTime.MinValue;
            _numMessages = 0;
        }

        public DateTime LatestMessageDate
        {
            get { return _latestMessageDate; }
        }

        public int NumberMessages
        {
            get { return _numMessages; }
        }

        public string HelperID
        {
            get
            {
                return "html";
            }
        }

        public string MailUri
        {
            get
            {
                iNotesConfig conf = iNotesConfig.Instance;
                return iNotesController.ReplaceUriTags(conf.NotesFileUrl + conf.HtmlUrlSuffix, null);
            }
        }

        public void Parse(FileInfo file, iNotesMailbox mbox)
        {
            _mailbox = mbox;
            parse(file);
        }

        public string MailLocalFileName
        {
            get { return "iNotesEmail.html"; }
        }

        private void ProcessElement(string element, Dictionary<string, string> attributes)
        {
            if ((element == "a") && attributes.ContainsKey("class") && attributes.ContainsKey("href"))
            {
                if (attributes["class"] == "entryLink")
                {
                    if (_current != null && _current.Sender.Length > 0)
                    {
                        _mailbox.Add(_current);
                    }

                    _current = new iNotesMessage();

                    string s, href = attributes["href"];
                    int i, j;
                    if (_numMessages == -1)
                    {
                        i = href.IndexOf("=TotalCount;") + 12;
                        j = href.IndexOf(",", i);
                        s = href.Substring(i, j - i);
                        if (!int.TryParse(s, out _numMessages)) _numMessages = 0;
                    }

                    i = href.IndexOf(")/") + 2;
                    j = href.IndexOf("/", i);
                    s = href.Substring(i, j - i);
                    _current.UniqueID = s;
                }
            }
            else if ((_current != null) && (element == "span") && (attributes.ContainsKey("class")))
            {
                _lastClass = attributes["class"];
                if (_lastClass.StartsWith("mailRowArea"))
                {
                    if (_lastClass.EndsWith(" unread"))
                    {
                        _current.IsNew = true;
                    }
                }
            }
        }

        private void ProcessLiteral(string literal)
        {
            if (_current != null && !string.IsNullOrEmpty(_lastClass))
            {
                if (_lastClass == "attArea")
                {
                    _current.HasAttachments = (literal.Trim() != string.Empty);
                }
                else if (_lastClass == "priorityArea")
                {
                    _current.Priority = literal;
                }
                else if (_lastClass == "dateArea")
                {
                    _current.DateString = literal;
                }
                else if (_lastClass == "senderArea")
                {
                    _current.Sender = literal;
                }
                else if (_lastClass == "subjectArea")
                {
                    if (string.IsNullOrEmpty(_current.Subject))
                        _current.Subject = literal;
                }
            }
        }

        protected void parse(FileInfo file)
        {
            string l_strHTML = File.ReadAllText(file.FullName);
            List<string> uriList = new List<string>();
            Dictionary<string, string> betweenTextItems = new Dictionary<string, string>();

            HtmlParseMode intMode = HtmlParseMode.Open;
            bool bReadScript = false;
            char chrCurr = ' ';
            string tagName = string.Empty;
            string tagText = string.Empty;
            string lastTagName = string.Empty;
            string betweenText = string.Empty;
            string lastUrl = string.Empty;
            StringBuilder literal = new StringBuilder();
            StringBuilder script = new StringBuilder();

            for (int i = 0; i < l_strHTML.Length; i++)
            {
                chrCurr = l_strHTML[i];

                if (betweenTextItems.Count > 0)
                {
                    Dictionary<string, string> changes = new Dictionary<string, string>();
                    foreach (string key in betweenTextItems.Keys)
                    {
                        changes[key] = betweenTextItems[key] + chrCurr;
                    }
                    foreach (string key in changes.Keys)
                    {
                        betweenTextItems[key] = changes[key];
                    }
                }

                if (intMode == HtmlParseMode.Open)
                {
                    if (chrCurr == '<')
                    {
                        tagName = "";
                        tagText = "";
                        intMode = HtmlParseMode.InElement;
                    }
                    else
                    {
                        literal.Append(chrCurr);
                    }

                    if (bReadScript) script.Append(chrCurr);

                    continue;
                }

                if (intMode == HtmlParseMode.InElement)
                {
                    if (literal.Length > 0)
                    {
                        string s = literal.ToString().Trim();
                        if (s.Length > 0)
                        {
                            this.ProcessLiteral(s);
                        }
                        literal.Remove(0, literal.Length);
                    }

                    if (chrCurr == '>') intMode = HtmlParseMode.ClosingElement;
                    else if (!((chrCurr == '\n') || (chrCurr == '\t') || (chrCurr == '\r') || (chrCurr == '\f') || (chrCurr == ' ')))
                        intMode = HtmlParseMode.ElementAttribute;
                    else if (bReadScript) script.Append(chrCurr);
                }

                if (intMode == HtmlParseMode.ElementAttribute)
                {
                    if (bReadScript && (tagName.Length >= 7) && !tagName.ToLower().StartsWith("/script"))
                    {
                        script.Append(chrCurr);
                        intMode = HtmlParseMode.Open;
                        continue;
                    }

                    if ((chrCurr == '>') || ((tagName.Length > 0) && (chrCurr == '/')))
                        intMode = HtmlParseMode.ClosingElement;
                    else if (!((chrCurr == '\n') || (chrCurr == '\t') || (chrCurr == '\r') || (chrCurr == '\f') || (chrCurr == ' ')))
                    {
                        tagName += chrCurr;
                        if (bReadScript) script.Append(chrCurr);
                    }
                    else intMode = HtmlParseMode.ClosingElement;
                }

                if (intMode == HtmlParseMode.ClosingElement)
                {
                    if (bReadScript)
                    {
                        script.Append(chrCurr);
                        if ((tagName.Length >= 7) && !tagName.ToLower().StartsWith("/script"))
                        {
                            intMode = HtmlParseMode.Open;
                            continue;
                        }
                    }

                    if (chrCurr != '>') tagText += chrCurr;
                    else
                    {
                        if (!bReadScript)
                        {
                            if (tagName.StartsWith("/"))
                            {
                            }
                            else if (!tagName.EndsWith("/") && !tagName.StartsWith("!"))
                            {
                                string rawtag = tagName.Trim().ToLower();

                                if ((tagName == "a") || (tagName == "title") || (tagName == "h1") || (tagName == "h2") || (tagName == "h3"))
                                {
                                    betweenTextItems[rawtag] = string.Empty;
                                }
                            }


                            if (!tagName.StartsWith("/") && !tagName.StartsWith("!"))
                            {
                                Dictionary<string, string> attrHash;
                                this.parseHTMLAttributes(tagName, tagText, out attrHash);
                                this.ProcessElement(tagName, attrHash);
                            }
                        }

                        if (tagName.ToLower().Equals("script"))
                        {
                            script.Remove(0, literal.Length);
                            bReadScript = true;
                        }
                        else if (tagName.ToLower().Equals("/script"))
                        {
                            bReadScript = false;
                        }

                        lastTagName = tagName;
                        intMode = HtmlParseMode.Open;
                    }
                }
            }
        }

        private void parseHTMLAttributes(string l_strTagName, string l_strTagText, out Dictionary<string, string> attrs)
        {
            char chrCurr = ' ';
            char chrBeforeLast = ' ';
            char chrLast = ' ';
            int intMode = 0;
            string tempStr = string.Empty;
            string fixedPath = string.Empty;
            string attName = string.Empty;
            string attValue = string.Empty;
            attrs = new Dictionary<string, string>();

            if (l_strTagName.StartsWith("!"))
            {
                attrs["content"] = l_strTagText;
            }
            else
            {
                for (int i = 0; i < l_strTagText.Length; i++)
                {
                    if (i > 1) chrBeforeLast = l_strTagText[i - 2]; else chrBeforeLast = ' ';
                    if (i > 0) chrLast = l_strTagText[i - 1]; else chrLast = ' ';
                    chrCurr = l_strTagText[i];

                    if (intMode == 0)
                    {
                        if ((chrCurr == '\n') || (chrCurr == '\t') || (chrCurr == '\r') || (chrCurr == '\f') || (chrCurr == ' '))
                        {
                            continue;
                        }
                        else
                        {
                            attName = "";
                            attValue = "";
                            intMode++;
                        }
                    }
                    if (intMode == 1)
                    {
                        if (chrCurr == '=')
                        {
                            ++intMode;
                        }
                        else if ((chrCurr == '\n') || (chrCurr == '\t') || (chrCurr == '\r') || (chrCurr == '\f') || (chrCurr == ' '))
                            ++intMode;
                        else
                            attName += chrCurr;
                    }
                    if (intMode == 2)
                    {
                        if (chrCurr == '=')
                        {
                            ++intMode;
                            continue;
                        }
                        else if ((chrCurr == '\n') || (chrCurr == '\t') || (chrCurr == '\r') || (chrCurr == '\f') || (chrCurr == ' '))
                            continue;
                        else
                        {
                            attrs[attName.ToLower()] = attValue;
                            intMode = 0;
                            --i;
                        }
                    }
                    if (intMode == 3)
                    {
                        if ((chrCurr == '\n') || (chrCurr == '\t') || (chrCurr == '\r') || (chrCurr == '\f') || (chrCurr == ' '))
                            continue;
                        else if (chrCurr == '\"')
                        {
                            intMode = 4;
                            continue;
                        }
                        else if (chrCurr == '\'')
                        {
                            intMode = 5;
                            continue;
                        }
                        else
                        {
                            intMode = 6;
                        }
                    }
                    if (intMode == 4)
                    {
                        if ((chrCurr == '\"') && ((chrLast != '\\') || ((chrBeforeLast == '\\') && (chrLast == '\\'))))
                        {
                            attrs[attName.ToLower()] = attValue;
                            intMode = 0;
                        }
                        else
                            attValue += chrCurr;
                    }
                    if (intMode == 5)
                    {
                        if ((chrCurr == '\'') && ((chrLast != '\\') || ((chrBeforeLast == '\\') && (chrLast == '\\'))))
                        {
                            attrs[attName.ToLower()] = attValue;
                            intMode = 0;
                        }
                        else
                            attValue += chrCurr;
                    }
                    if (intMode == 6)
                    {
                        if ((chrCurr == '\n') || (chrCurr == '\t') || (chrCurr == '\r') || (chrCurr == '\f') || (chrCurr == ' '))
                        {
                            attrs[attName.ToLower()] = attValue;
                            intMode = 0;
                        }
                        else if (i == (l_strTagText.Length - 1))
                        {
                            attValue += chrCurr;
                            attrs[attName.ToLower()] = attValue;
                            intMode = 0;
                        }
                        else
                            attValue += chrCurr;
                    }
                }
            }

            string jsTemp = "";
            jsTemp += !attrs.ContainsKey("onload") ? "" : attrs["onload"];
            jsTemp += !attrs.ContainsKey("onclick") ? "" : attrs["onclick"];
            jsTemp += !attrs.ContainsKey("ondblclick") ? "" : attrs["ondblclick"];
            jsTemp += !attrs.ContainsKey("onchange") ? "" : attrs["onchange"];
            jsTemp += !attrs.ContainsKey("onkeypress") ? "" : attrs["onkeypress"];

            if (!string.IsNullOrEmpty(jsTemp))
            {
                //newUris.AddRange(this.parseJavaScript(jsTemp));
            }

            if (l_strTagName.Equals("a", StringComparison.CurrentCultureIgnoreCase) || l_strTagName.Equals("area", StringComparison.CurrentCultureIgnoreCase) || l_strTagName.Equals("link", StringComparison.CurrentCultureIgnoreCase))
            {
                // get href
                tempStr = !attrs.ContainsKey("href") ? "" : attrs["href"];
                tempStr = tempStr.Trim();

                if (checkStrPath(tempStr))
                {
                   // fixedPath = this._context.Browser.FixUrl(tempStr);
                }
            }
            else if (l_strTagName.Equals("img", StringComparison.CurrentCultureIgnoreCase) || l_strTagName.Equals("applet", StringComparison.CurrentCultureIgnoreCase)
                    || l_strTagName.Equals("embed", StringComparison.CurrentCultureIgnoreCase) || l_strTagName.Equals("bgsound", StringComparison.CurrentCultureIgnoreCase)
                    || l_strTagName.Equals("iframe", StringComparison.CurrentCultureIgnoreCase) || l_strTagName.Equals("frame", StringComparison.CurrentCultureIgnoreCase)
                    || l_strTagName.Equals("xml", StringComparison.CurrentCultureIgnoreCase) || l_strTagName.Equals("script", StringComparison.CurrentCultureIgnoreCase) || l_strTagName.Equals("input", StringComparison.CurrentCultureIgnoreCase))
            {
                // get src
                tempStr = !attrs.ContainsKey("src") ? "" : attrs["src"];
                tempStr = tempStr.Trim();
                if (checkStrPath(tempStr))
                {
                   // fixedPath = this._context.Browser.FixUrl(tempStr);
                }
            }
            else if (l_strTagName.Equals("meta", StringComparison.CurrentCultureIgnoreCase)) //http-equiv="refresh" content="5;url=http://wikipedia.org"
            {
                // get action
                if (attrs.ContainsKey("http-equiv") && (attrs["http-equiv"].ToLower() == "refresh"))
                {
                    tempStr = !attrs.ContainsKey("content") ? "" : attrs["content"];
                    tempStr = tempStr.Trim();
                    if (tempStr.IndexOf("url=", StringComparison.CurrentCultureIgnoreCase) >= 0) tempStr = tempStr.Substring(tempStr.IndexOf("url=", StringComparison.CurrentCultureIgnoreCase) + 4);
                    if (checkStrPath(tempStr))
                    {
                        //fixedPath = this._context.Browser.FixUrl(tempStr);
                    }
                }
            }
            else if (l_strTagName.Equals("form", StringComparison.CurrentCultureIgnoreCase))
            {
                // get action
                tempStr = !attrs.ContainsKey("action") ? "" : attrs["action"];
                tempStr = tempStr.Trim();
                if (checkStrPath(tempStr))
                {
                    //fixedPath = this._context.Browser.FixUrl(tempStr);
                }
            }
            else if (l_strTagName.Equals("table", StringComparison.CurrentCultureIgnoreCase) || l_strTagName.Equals("body", StringComparison.CurrentCultureIgnoreCase))
            {
                // get background
                tempStr = !attrs.ContainsKey("background") ? "" : attrs["background"];
                tempStr = tempStr.Trim();
                if (checkStrPath(tempStr))
                {
                    //fixedPath = this._context.Browser.FixUrl(tempStr);
                }
            }
            else if (l_strTagName.Equals("option", StringComparison.CurrentCultureIgnoreCase))
            {
                // get background
                tempStr = !attrs.ContainsKey("value") ? "" : attrs["value"];
                tempStr = tempStr.Trim();
                if (checkStrPath(tempStr))
                {
                    //fixedPath = this._context.Browser.FixUrl(tempStr);
                }
            }
            //return newUris;
        }

        private bool checkStrPath(string l_temp)
        {
            //If it starts with a ?, it's a good path
            if (l_temp.StartsWith("?")) return true;

            // Get rid of any anchor crapola
            int anIndex = l_temp.IndexOf('#') == -1 ? l_temp.Length : l_temp.IndexOf('#');
            l_temp = l_temp.Substring(0, anIndex);

            if (l_temp.ToLower().IndexOf("mailto:") >= 0) return false;

            if (l_temp.StartsWith("/") || l_temp.ToLower().StartsWith("http://")
                            || l_temp.StartsWith("./") || l_temp.StartsWith("../"))
                return true;

            int qsIndex = l_temp.IndexOf('?') == -1 ? l_temp.Length : l_temp.IndexOf('?');
            int beginIndex = (qsIndex - 7) < 0 ? 0 : (qsIndex - 7);

            if (l_temp.Substring(beginIndex, qsIndex - beginIndex).IndexOf('.') >= 0)
                return true;
            else
                return false;
        }

        private bool legalDomain(string l_temp)
        {
            return true;
        }
    }
}
